﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using Xajhzwb.Components.Data;
using System.Threading;
using System.IO;
using Xajhzwb.Components.Util;
using System.Data.SqlClient;
using System.Data.OleDb;
using MySql.Data.MySqlClient;
using System.Text.RegularExpressions;
using Xajhzwb.Components.Helper;

namespace Xajhzwb.Components.Publish
{
    public class PublishTask
    {
        public int TaskID;
        public TaskData TaskData = new TaskData();

        public PublishTask(int taskID, TaskData taskData)
        {
            TaskID = taskID;
            TaskData = taskData;
        }

        ~PublishTask()
        {

        }

        #region Event
        private readonly Object m_eventLock = new Object();

        private event EventHandler<PublishCompletedEventArgs> e_PublishCompleted;
        internal event EventHandler<PublishCompletedEventArgs> PublishCompleted
        {
            add { lock(m_eventLock) { e_PublishCompleted += value; } }
            remove { lock(m_eventLock) { e_PublishCompleted -= value; } }
        }

        private event EventHandler<PublishFailedEventArgs> e_PublishFailed;
        internal event EventHandler<PublishFailedEventArgs> PublishFailed
        {
            add { lock(m_eventLock) { e_PublishFailed += value; } }
            remove { lock(m_eventLock) { e_PublishFailed -= value; } }
        }

        private event EventHandler<PublishStartedEventArgs> e_PublishStarted;
        internal event EventHandler<PublishStartedEventArgs> PublishStarted
        {
            add { lock(m_eventLock) { e_PublishStarted += value; } }
            remove { lock(m_eventLock) { e_PublishStarted -= value; } }
        }

        private event EventHandler<PublishErrorEventArgs> e_PublishError;
        internal event EventHandler<PublishErrorEventArgs> PublishError
        {
            add { lock(m_eventLock) { e_PublishError += value; } }
            remove { lock(m_eventLock) { e_PublishError -= value; } }
        }

        private event EventHandler<PublishTempDataCompletedEventArgs> e_PublishTempDataCompleted;
        internal event EventHandler<PublishTempDataCompletedEventArgs> PublishTempDataCompleted
        {
            add { lock(m_eventLock) { e_PublishTempDataCompleted += value; } }
            remove { lock(m_eventLock) { e_PublishTempDataCompleted -= value; } }
        }

        private event EventHandler<PublishLogEventArgs> e_PublishLog;
        internal event EventHandler<PublishLogEventArgs> PublishLog
        {
            add { lock(m_eventLock) { e_PublishLog += value; } }
            remove { lock(m_eventLock) { e_PublishLog -= value; } }
        }

        //private event EventHandler<cRunTaskEventArgs> e_RunTask;
        //internal event EventHandler<cRunTaskEventArgs> RunTask
        //{
        //    add { lock(m_eventLock) { e_RunTask += value; } }
        //    remove { lock(m_eventLock) { e_RunTask -= value; } }
        //}
        #endregion

        private Thread m_Thread;
        private readonly Object m_threadLock = new Object();

        #region TempData
        public void startSaveTempData()
        {
            lock(m_threadLock)
            {
                m_Thread = new Thread(this.SaveTempData);
                m_Thread.Name = TaskData.FileName;
                m_Thread.Start();
            }
        }

        private readonly Object m_fileLock = new Object();
        private void SaveTempData()
        {
            try
            {
                if(File.Exists(TaskData.FileName))
                {
                    lock(m_fileLock)
                    {
                        File.Delete(TaskData.FileName);
                    }
                }

                TaskData.TempData.WriteXml(TaskData.FileName, XmlWriteMode.WriteSchema);
                e_PublishTempDataCompleted(this, new PublishTempDataCompletedEventArgs(this.TaskData.TaskID, this.TaskData.TaskName));
            }
            catch(System.Exception ex)
            {
                if(e_PublishLog != null)
                {
                    WriteLog(ex.Message);
                    e_PublishLog(this, new PublishLogEventArgs(this.TaskData.TaskID, ((int)Const.LogType.Error).ToString() + "任务：" + this.TaskData.TaskName + "临时存储失败，错误信息为：" + ex.Message + "\n"));

                }

                if(e_PublishError != null)
                {
                    e_PublishError(this, new PublishErrorEventArgs(this.TaskData.TaskID, this.TaskData.TaskName, ex));
                }
            }
        }
        #endregion

        public void startPublic()
        {
            lock(m_threadLock)
            {
                m_Thread = new Thread(this.ThreadWork);
                //m_Thread.Name = TaskData.FileName;
                m_Thread.Start();
            }
        }

        private void ThreadWork()
        {
            try
            {
                ExportData();
            }
            catch(System.Exception ex)
            {
                e_PublishError(this, new PublishErrorEventArgs(this.TaskData.TaskID, this.TaskData.TaskName, ex));
            }
        }

        private bool ExportData()
        {
            PublishStartedEventArgs evt = new PublishStartedEventArgs(this.TaskData.TaskID, this.TaskData.TaskName);
            e_PublishStarted(this, evt);

            switch(TaskData.PublishType)
            {
                case (int)Const.PublishType.PublishWeb:
                    ExportWeb();
                    break;
                case (int)Const.PublishType.PublishTxt:
                    ExportTxt();
                    break;
                case (int)Const.PublishType.PublishExcel:
                    ExportExcel();
                    break;
                case (int)Const.PublishType.PublishAccess:
                    ExportAccess();
                    break;
                case (int)Const.PublishType.PublishMsSql:
                    ExportMsSql();
                    break;
                case (int)Const.PublishType.PublishMySql:
                    ExportMySql();
                    break;
                default:
                    break;
            }

            PublishCompletedEventArgs evt1 = new PublishCompletedEventArgs(this.TaskData.TaskID, this.TaskData.TaskName);

            e_PublishCompleted(this, evt1);

            //TriggerRun();

            return true;
        }

        #region ExportExcel
        private void ExportExcel()
        {
            string TaskName = TaskData.TaskName;
            string FileName = TaskData.ExportFile;
            System.Data.DataTable gData = TaskData.TempData;

            Utils.CreateDirectory(FileName);

            FileStream myStream = File.Open(FileName, FileMode.Create, FileAccess.Write, FileShare.Write);
            StreamWriter sw = new StreamWriter(myStream, System.Text.Encoding.GetEncoding("gb2312"));
            string str = "";
            string tempStr = "";
            int i = 0;
            int Count = 0;

            try
            {
                if(TaskData.IsExportHeader == true)
                {
                    for(i = 0; i < gData.Columns.Count; i++)
                    {
                        str += "\t";
                        str += gData.Columns[i].ColumnName;
                    }

                    sw.WriteLine(str);
                }

                Count = gData.Rows.Count;
                for(i = 0; i < gData.Rows.Count; i++)
                {
                    for(int j = 0; j < gData.Columns.Count; j++)
                    {

                        tempStr += "\t";
                        tempStr += gData.Rows[i][j];
                    }
                    sw.WriteLine(tempStr);
                    tempStr = "";

                }

                sw.Close();
                myStream.Close();

            }
            catch(Exception ex)
            {
                if(e_PublishLog != null)
                {
                    WriteLog(ex.Message);
                    e_PublishLog(this, new PublishLogEventArgs(this.TaskData.TaskID, ((int)Const.LogType.Error).ToString() + "任务：" + this.TaskData.TaskName + "发布" + FileName + "失败，错误信息为：" + ex.Message + "\n"));
                }

                return;
            }
            finally
            {
                sw.Close();
                myStream.Close();

            }

            return;
        }
        #endregion

        #region ExportTxt
        private void ExportTxt()
        {
            string TaskName = TaskData.TaskName;
            string FileName = TaskData.ExportFile;
            System.Data.DataTable gData = TaskData.TempData;

            Utils.CreateDirectory(FileName);

            FileStream myStream = File.Open(FileName, FileMode.Create, FileAccess.Write, FileShare.Write);
            StreamWriter sw = new StreamWriter(myStream, System.Text.Encoding.GetEncoding("gb2312"));
            string str = "";
            string tempStr = "";

            try
            {
                if(this.TaskData.IsExportHeader == true)
                {
                    for(int i = 0; i < gData.Columns.Count; i++)
                    {
                        str += "\t";
                        str += gData.Columns[i].ColumnName;
                    }

                    sw.WriteLine(str);
                }

                for(int i = 0; i < gData.Rows.Count; i++)
                {
                    for(int j = 0; j < gData.Columns.Count; j++)
                    {

                        tempStr += "\t";
                        tempStr += gData.Rows[i][j];
                    }
                    sw.WriteLine(tempStr);
                    tempStr = "";
                }


                sw.Close();
                myStream.Close();

            }
            catch(Exception ex)
            {
                if(e_PublishLog != null)
                {
                    WriteLog(ex.Message);
                    e_PublishLog(this, new PublishLogEventArgs(this.TaskData.TaskID, ((int)Const.LogType.Error).ToString() + "任务：" + this.TaskData.TaskName + "发布" + FileName + "失败，错误信息为：" + ex.Message + "\n"));
                }

                return;
            }
            finally
            {
                sw.Close();
                myStream.Close();
            }

            return;
        }
        #endregion

        #region getCreateTablesql
        private string getCreateTablesql(Const.PublishType publishType, string Encoding)
        {
            string strsql = "";

            strsql = "create table " + this.TaskData.DataTableName + "(";
            for(int i = 0; i < TaskData.TempData.Columns.Count; i++)
            {
                switch(publishType)
                {
                    case Const.PublishType.PublishAccess:
                        strsql += TaskData.TempData.Columns[i].ColumnName + " " + "text" + ",";
                        break;
                    case Const.PublishType.PublishMsSql:
                        strsql += TaskData.TempData.Columns[i].ColumnName + " " + "text" + ",";
                        break;
                    case Const.PublishType.PublishMySql:
                        strsql += TaskData.TempData.Columns[i].ColumnName + " " + "text" + ",";
                        break;
                    default:
                        strsql += TaskData.TempData.Columns[i].ColumnName + " " + "text" + ",";
                        break;
                }
            }
            strsql = strsql.Substring(0, strsql.Length - 1);
            strsql += ")";

            if(publishType == Const.PublishType.PublishMySql)
            {
                if(Encoding == "" || Encoding == null)
                    Encoding = "utf8";

                strsql += " CHARACTER SET " + Encoding + " ";
            }

            return strsql;
        }
        #endregion

        #region ExportAccess
        private void ExportAccess()
        {
            bool IsTable = false;

            OleDbConnection conn = new OleDbConnection();
            string connectionstring = TaskData.DataSource;
            string tName = TaskData.DataTableName;
            conn.ConnectionString = connectionstring;

            try
            {
                conn.Open();
            }
            catch(System.Exception ex)
            {
                if(e_PublishLog != null)
                {
                    WriteLog(ex.Message);
                    e_PublishLog(this, new PublishLogEventArgs(this.TaskData.TaskID, ((int)Const.LogType.Error).ToString() + "任务：" + this.TaskData.TaskName + "发布Access失败，错误信息为：" + ex.Message + "\n"));
                }

                return;
            }

            System.Data.DataTable tb = conn.GetSchema("Tables");
            foreach(DataRow r in tb.Rows)
            {
                if(r[3].ToString() == "TABLE")
                {
                    if(r[2].ToString() == tName)
                    {
                        IsTable = true;
                        break;
                    }
                }

            }

            if(IsTable == false)
            {
                string CreateTablesql = getCreateTablesql(Const.PublishType.PublishAccess, "");
                OleDbCommand com = new OleDbCommand();
                com.Connection = conn;
                com.CommandText = CreateTablesql;
                com.CommandType = CommandType.Text;
                try
                {
                    int result = com.ExecuteNonQuery();
                }
                catch(System.Data.OleDb.OleDbException ex)
                {
                    if(ex.ErrorCode != -2147217900)
                    {
                        if(e_PublishLog != null)
                        {
                            WriteLog(ex.Message);
                            e_PublishLog(this, new PublishLogEventArgs(this.TaskData.TaskID, ((int)Const.LogType.Error).ToString() + "任务：" + this.TaskData.TaskName + "发布MySql失败，错误信息为：" + ex.Message + "\n"));
                        }

                        throw ex;
                    }
                }

                try
                {

                    System.Data.OleDb.OleDbDataAdapter da = new System.Data.OleDb.OleDbDataAdapter("SELECT * FROM " + tName, conn);
                    System.Data.OleDb.OleDbCommandBuilder builder = new System.Data.OleDb.OleDbCommandBuilder(da);

                    DataSet ds = new DataSet();
                    da.Fill(ds, TaskData.DataTableName);

                    for(int i = 0; i < TaskData.TempData.Rows.Count; i++)
                    {
                        DataRow dr = ds.Tables[0].NewRow();
                        for(int j = 0; j < TaskData.TempData.Columns.Count; j++)
                        {
                            dr[j] = TaskData.TempData.Rows[i][j].ToString();
                        }
                        ds.Tables[0].Rows.Add(dr);
                    }
                    int m = da.Update(ds.Tables[0]);
                }
                catch(System.Exception ex)
                {
                    if(e_PublishLog != null)
                    {
                        WriteLog(ex.Message);
                        e_PublishLog(this, new PublishLogEventArgs(this.TaskData.TaskID, ((int)Const.LogType.Error).ToString() + "任务：" + this.TaskData.TaskName + "发布Access失败，错误信息为：" + ex.Message + "\n"));
                    }

                    return;
                }

            }
            else
            {
                try
                {
                    //无需建立新表，需要采用sql语句的方式进行，但需要替换sql语句中的内容
                    System.Data.OleDb.OleDbCommand cm = new System.Data.OleDb.OleDbCommand();
                    cm.Connection = conn;
                    cm.CommandType = CommandType.Text;

                    //开始拼sql语句
                    string sql = "";

                    for(int i = 0; i < TaskData.TempData.Rows.Count; i++)
                    {
                        sql = TaskData.InsertSql;

                        for(int j = 0; j < TaskData.TempData.Columns.Count; j++)
                        {
                            string strPara = "{" + TaskData.TempData.Columns[j].ColumnName + "}";
                            //string strParaValue = m_pTaskData.PublishData.Rows[i][j].ToString();
                            string strParaValue = TaskData.TempData.Rows[i][j].ToString().Replace("\"", "\"\"");
                            sql = sql.Replace(strPara, strParaValue);
                        }

                        cm.CommandText = sql;
                        cm.ExecuteNonQuery();
                    }
                }
                catch(System.Exception ex)
                {
                    if(e_PublishLog != null)
                    {
                        WriteLog(ex.Message);
                        e_PublishLog(this, new PublishLogEventArgs(this.TaskData.TaskID, ((int)Const.LogType.Error).ToString() + "任务：" + this.TaskData.TaskName + "发布Access失败，错误信息为：" + ex.Message + "\n"));
                    }

                    return;
                }

            }


            conn.Close();
        }
        #endregion

        #region ExportMsSql
        private void ExportMsSql()
        {
            bool IsTable = false;

            SqlConnection conn = new SqlConnection();
            string connectionstring = TaskData.DataSource;
            string tName = TaskData.DataTableName;
            conn.ConnectionString = connectionstring;

            try
            {
                conn.Open();
            }
            catch(System.Exception ex)
            {
                if(e_PublishLog != null)
                {
                    WriteLog(ex.Message);
                    e_PublishLog(this, new PublishLogEventArgs(this.TaskData.TaskID, ((int)Const.LogType.Error).ToString() + "任务：" + this.TaskData.TaskName + "发布MSSql失败，错误信息为：" + ex.Message + "\n"));
                }

                throw ex;
            }

            System.Data.DataTable tb = conn.GetSchema("Tables");

            foreach(DataRow r in tb.Rows)
            {
                if(r[2].ToString() == tName)
                {
                    IsTable = true;
                    break;
                }
            }

            if(IsTable == false)
            {
                string CreateTablesql = getCreateTablesql(Const.PublishType.PublishMsSql, "");

                SqlCommand com = new SqlCommand();
                com.Connection = conn;
                com.CommandText = CreateTablesql;
                com.CommandType = CommandType.Text;
                try
                {
                    int result = com.ExecuteNonQuery();
                }
                catch(System.Data.SqlClient.SqlException ex)
                {
                    if(ex.ErrorCode != -2147217900)
                    {
                        if(e_PublishLog != null)
                        {
                            WriteLog(ex.Message);
                            e_PublishLog(this, new PublishLogEventArgs(this.TaskData.TaskID, ((int)Const.LogType.Error).ToString() + "任务：" + this.TaskData.TaskName + "发布MSSql失败，错误信息为：" + ex.Message + "\n"));
                        }

                        throw ex;
                    }
                }
            }

            SqlCommand cm = new SqlCommand();
            cm.Connection = conn;
            cm.CommandType = CommandType.Text;
            string strInsertSql = TaskData.InsertSql;

            string sql = "";

            for(int i = 0; i < TaskData.TempData.Rows.Count; i++)
            {
                sql = strInsertSql;

                for(int j = 0; j < TaskData.TempData.Columns.Count; j++)
                {
                    string strPara = "{" + TaskData.TempData.Columns[j].ColumnName + "}";
                    //string strParaValue = m_pTaskData.PublishData.Rows[i][j].ToString();
                    string strParaValue = TaskData.TempData.Rows[i][j].ToString().Replace("\"", "\"\"");
                    sql = sql.Replace(strPara, strParaValue);
                }
                try
                {
                    cm.CommandText = sql;
                    cm.ExecuteNonQuery();
                }
                catch(System.Exception ex)
                {
                    if(e_PublishLog != null)
                    {
                        WriteLog(ex.Message);
                        e_PublishLog(this, new PublishLogEventArgs(this.TaskData.TaskID, ((int)Const.LogType.Error).ToString() + "任务：" + this.TaskData.TaskName + "发布MSSql失败，Sql语句为：" + sql.ToString() + " 错误信息为：" + ex.Message + "\n"));
                    }

                }
            }
            //}
            conn.Close();
        }
        #endregion

        #region ExportMySql
        private void ExportMySql()
        {
            bool IsTable = false;

            MySqlConnection conn = new MySqlConnection();
            string connectionstring = TaskData.DataSource;
            string tName = TaskData.DataTableName;
            conn.ConnectionString = connectionstring;

            try
            {
                conn.Open();
            }
            catch(System.Exception ex)
            {
                if(e_PublishLog != null)
                {
                    WriteLog(ex.Message);
                    e_PublishLog(this, new PublishLogEventArgs(this.TaskData.TaskID, ((int)Const.LogType.Error).ToString() + "任务：" + this.TaskData.TaskName + "发布MySql失败，错误信息为：" + ex.Message + "\n"));
                }
                throw ex;
            }

            System.Data.DataTable tb = conn.GetSchema("Tables");
            foreach(DataRow r in tb.Rows)
            {
                if(string.Compare(r[2].ToString(), tName, true) == 0)
                {
                    IsTable = true;
                    break;
                }
            }

            if(IsTable == false)
            {
                string strMatch = "(?<=character set=)[^\\s]*(?=[\\s;])";
                Match s = Regex.Match(connectionstring, strMatch, RegexOptions.IgnoreCase);
                string Encoding = s.Groups[0].Value;

                string CreateTablesql = getCreateTablesql(Const.PublishType.PublishMySql, Encoding);
                MySqlCommand com = new MySqlCommand();
                com.Connection = conn;
                com.CommandText = CreateTablesql;
                com.CommandType = CommandType.Text;
                try
                {
                    int result = com.ExecuteNonQuery();
                }
                catch(MySql.Data.MySqlClient.MySqlException ex)
                {
                    if(ex.ErrorCode != -2147217900)
                    {
                        if(e_PublishLog != null)
                        {
                            WriteLog(ex.Message);
                            e_PublishLog(this, new PublishLogEventArgs(this.TaskData.TaskID, ((int)Const.LogType.Error).ToString() + "任务：" + this.TaskData.TaskName + "发布MySql失败，错误信息为：" + ex.Message + "\n"));
                        }
                        throw ex;
                    }
                }
            }

            //无需建立新表，需要采用sql语句的方式进行，但需要替换sql语句中的内容
            MySqlCommand cm = new MySqlCommand();
            cm.Connection = conn;
            cm.CommandType = CommandType.Text;

            //开始拼sql语句
            string strInsertSql = TaskData.InsertSql;

            //需要将双引号替换成单引号
            //strInsertSql = strInsertSql.Replace("\"", "'");


            string sql = "";



            for(int i = 0; i < TaskData.TempData.Rows.Count; i++)
            {
                sql = strInsertSql;

                for(int j = 0; j < TaskData.TempData.Columns.Count; j++)
                {
                    string strPara = "{" + TaskData.TempData.Columns[j].ColumnName + "}";
                    string strParaValue = TaskData.TempData.Rows[i][j].ToString().Replace("\"", "\"\"");
                    sql = sql.Replace(strPara, strParaValue);
                }

                try
                {
                    cm.CommandText = sql;
                    cm.ExecuteNonQuery();
                }
                catch(System.Exception ex)
                {
                    if(e_PublishLog != null)
                    {
                        WriteLog(ex.Message);
                        e_PublishLog(this, new PublishLogEventArgs(this.TaskData.TaskID, ((int)Const.LogType.Error).ToString() + "任务：" + this.TaskData.TaskName + "发布MySql失败，Sql语句为：" + sql.ToString() + " 错误信息为：" + ex.Message + "\n"));
                    }

                }
            }

            conn.Close();
        }
        #endregion

        private void ExportWeb()
        {
            for(int i = 0; i < TaskData.TempData.Rows.Count; i++)
            {
                string requestUrl = TaskData.PublishData.UrlPost;





                if(!string.IsNullOrEmpty(TaskData.PublishData.CodePage))
                {
                    requestUrl = Utils.UrlEncode(requestUrl);
                }


                try
                {
                    string returnCode = TaskData.PublishData.PostOkCode;    
                }
                catch(System.Exception ex)
                {
                    if(e_PublishLog != null)
                    {
                        WriteLog(ex.Message);
                        e_PublishLog(this, new PublishLogEventArgs(this.TaskData.TaskID, ((int)Const.LogType.Error).ToString() + "任务：" + this.TaskData.TaskName + "发布WEB失败，错误信息为：" + ex.Message + "\n"));
                    }

                    return;
                }
            }
        }


        private void WriteLog(string logMessage)
        {
            LogHelper.WriteLog(TaskData.TaskName, LogHelper.LogType.PublishError, logMessage);
        }
    }
}
